library(tidyverse)
── Attaching core tidyverse packages ───────────────
✔ dplyr     1.1.2     ✔ readr     2.1.4
✔ forcats   1.0.0     ✔ stringr   1.5.0
✔ ggplot2   3.4.2     ✔ tibble    3.2.1
✔ lubridate 1.9.2     ✔ tidyr     1.3.0
✔ purrr     1.0.1     ── Conflicts ────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag()    masks stats::lag()
ℹ Use the ]8;;http://conflicted.r-lib.org/conflicted package]8;; to force all conflicts to become errors
library(usmap)
library(ggplot2)
library(broom)
library(lubridate)
library(plotly)
Registered S3 method overwritten by 'data.table':
  method           from
  print.data.table     
Registered S3 method overwritten by 'htmlwidgets':
  method           from         
  print.htmlwidget tools:rstudio

Attaching package: ‘plotly’

The following object is masked from ‘package:ggplot2’:

    last_plot

The following object is masked from ‘package:stats’:

    filter

The following object is masked from ‘package:graphics’:

    layout
### Read in data
marathon_usa_sex_pace <- read_csv("data/marathon_usa_sex_pace.csv")
Rows: 102 Columns: 4── Column specification ───────────────────────────────────────────────────
Delimiter: ","
chr (2): state, Sex
dbl (2): number, mean_pace
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
### create a choropleth
p <- plot_usmap(data = marathon_usa_sex_pace, values = "number", color = "black",)+scale_size_continuous(range = c(min(marathon_usa_sex_pace$n), max(marathon_usa_sex_pace$n)))+  scale_fill_continuous(
    low = "#FEEBE7", high = "red", name = "Total", label = scales::comma
  ) + theme(legend.position = "right")+
  facet_wrap(~ Sex,ncol = 1,labeller = as_labeller(c('F' = "Number of Female Pariticpants", 'M' = "Number of Male Participants"))) +ggtitle(label = "Boston Marathon 2017")
Warning: Unknown or uninitialised column: `n`.Warning: no non-missing arguments to min; returning InfWarning: Unknown or uninitialised column: `n`.Warning: no non-missing arguments to max; returning -Inf
p2<-p + theme(
  legend.position = c(1, .3), 
  legend.background = element_rect(fill = "white", colour = NA),
  strip.background = element_blank(),
 plot.title = element_text(size=20),
 strip.text = element_text(size=15),
 panel.spacing = unit(2, "lines"),
  plot.caption = element_text("State of Participants Origin")
 
)
#ggplotly(p2) 

####model


### read in and process data
marathon <- read_csv("data/marathon.csv")
Rows: 26410 Columns: 21── Column specification ────────────────────────────
Delimiter: ","
chr   (6): Bib, Name, M/F, City, State, Country
dbl   (4): Age, Overall, Gender, Division
time (11): fiveK, tenK, fifteenK, twentyK, Half,...
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
marathon <- na.omit(marathon)
marathon$Half<- hms(marathon$Half)
marathon$OfficialTime<- hms(marathon$OfficialTime)
marathon$tenK<- hms(marathon$tenK)
marathon$thirtyK<- hms(marathon$thirtyK)
marathon$Pace<- hms(marathon$Pace)

marathon$Half<- as.numeric(marathon$Half)
marathon$OfficialTime<- as.numeric(marathon$OfficialTime)
marathon$tenK<- as.numeric(marathon$tenK)
marathon$thirtyK<- as.numeric(marathon$thirtyK)
marathon$Pace<- as.numeric(marathon$Pace)
### create models
m2_model <- lm(OfficialTime ~ tenK + Half + thirtyK,
                    data = marathon)
tidy(m2_model)
m2_coefs <- tidy(m2_model, conf.int = TRUE) %>% 
  filter(term != "(Intercept)")  
#m2_coefs
m3_model <- lm(OfficialTime ~ tenK + Half + thirtyK+Age,
                    data = marathon)
tidy(m3_model)
m3_coefs <- tidy(m3_model, conf.int = TRUE) %>% 
  filter(term != "(Intercept)")  
#m3_coefs
###create coefficent plot
lables2<-c("30K","10K", "Half Race","Age")

pco<-ggplot(m3_coefs,
       aes(x = estimate, 
           y = fct_rev(term))) +
  geom_pointrange(aes(xmin = conf.low, 
                      xmax = conf.high, color=fct_rev(term)),size=.75) +
  geom_vline(xintercept = 0, 
             color = "purple") + 
  scale_color_brewer(palette="Set1")+
  theme_minimal()+labs(title = "Linear Model Coefficents for Finish Time", x= "Estimate Coefficent", y="Distance Run")+scale_color_discrete(name="Distance Run", labels=lables2)+scale_y_discrete(labels=lables2)
Scale for colour is already present.
Adding another scale for colour, which will replace the existing scale.
#pco
ggplotly(p2) 

Spatial Visualization

  1. What I originally wanted to make was a world map showing the participants origins. However when going through the data it become apparent that there wasn’t high number participants represented outside the USA in comparison to inside the USA. So I switched to a USA map and decided to show the participants by state. I further divided the data by Sex to see if there were any visual differences. The steps I took were filtering out the non USA participants and then further dividing them up by sex. I then summed the amount of each per state and created a new data frame to graph the data. Finally I wanted to have something interactive so I decided to use ggplotly so you can see the individual numbers per state.

  2. Looking at this map you can see two things. That the general distribution of male and female participants is very similar as the colors for each state look similar. Also you can see which states have the most participants with Massachusetts having the most. This makes sense because the marathon is hosted in Boston. However whats interesting the second state is California. I think this is interesting because California is so far away from Massachusetts. It’s also fun to see that they also had participants from Alaska and Hawaii.

  3. I kept the design simple and used a base red color to make the populations stand out more, and kept it to one color. I made the title left aligned because the viewers eyes tend to view the left. I used a facet style graph to show side by side the male and female participants in a way that was easy to see. I used ggploty to make the map interactive so you can hover over every plot and see the numbers. This draws in the user to use the map.

ggplot() +
  geom_smooth(aes(x = tenK, y = OfficialTime), data = m2_model, 
              method = "lm", se = FALSE, color = "red4") + 
  geom_smooth(aes(x = Half, y = OfficialTime), data = m2_model, 
              method = "lm", se = FALSE, color = "blue4") + 
  geom_smooth(aes(x = thirtyK, y = OfficialTime), data = m2_model, 
              method = "lm", se = FALSE, color = "green4") + 
  geom_point(aes(x = tenK, y = OfficialTime), data = m2_model, color = "red",alpha = 0.02)+
  geom_point(aes(x = Half, y = OfficialTime), data = m2_model, color = "blue",alpha = 0.02) +
  geom_point(aes(x = thirtyK, y = OfficialTime), data = m2_model, color = "green",alpha = 0.02)+ 
annotate('text', x = 5100, y = 27000, label = 'Ten K',size = 5,angle='68', color= 'red4')+ 
annotate('text', x = 11000, y = 25500, label = 'Half Race',size = 5,angle='51', color= 'blue4')+ 
annotate('text', x = 18000, y = 27500, label = 'Thrity K',size = 5,angle='41', color= 'green4')+labs(
  title = "Linear Model Line for Offical Time by Distance Time", x= "Distance Time in Seconds", y="Finish Time in Seconds")+theme_minimal()

NA
NA

Linear Model Line Plot

  1. For the model I originally planed to create a line with geom_smooth and a linear model. I created a linear model then used the linear model data to draw three lines with its associated plot cloud. I also had to convert the time to seconds. I also originally wanted to plot age but it didn’t turn out good.

  2. Looking at the data you can see the plot cloud for the three different distances over Finish time. You can see where each distance as a linear model and how it associates with what it predicts where the finish time should be compared to the time at the associated distance. You can see the slopes of the predicted lines. The story you can tell here is you can follow the line and see if you passed a distance at x time your finish them will likely be y time. A runner can use this to target times they need to meet. This is followed for each of the three distances. I had difficulty here adding Age as a component it doesn’t seem to create a usable line.

  3. I continued to keep the design simple with bright colors to clash against the white background. I’m a fan of theme_minimal and think it does a good job of decluttering the graph. I added a opacity to the plot points because they were so thick you couldn’t see the lines. For each line I added an annotation to identify which line goes to with variable distance.

pco

Model Visualization Coefficient Plot

  1. For the model I originally planed to create a coefficient plot. I wanted to have more elements originally but I decided to keep it simple and limit it to four plot elements, early in the race, middle of the race and late in the race and finally age. I found that adding more distances was somewhat redundant and complicated the model. The steps I took were running the variables through a linear model, then getting the coefficients and converting the information into to tidy data.

  2. Looking at this map you can see the coefficients and it has a vertical line at zero. Points that are close to the zero don’t have much bearing on the outcome. Looking at the plots you can see that 10K is close to the zero line. You can also see that Half race has a value of -1.3 which has a negative influence on the outcome and that 30K is 2.3 positive and has very strong bearing on the overcome of the Finish Time. The Story here is that how you do early in the race has much less effect on your finishing time than how you do later in the race. One last coefficient I threw in here for the graph is Age, you see that Age age has large bearing on your Finish Time. Difficulties I had were the linear model function in R would not take it in time properly I had to change all the times to seconds.

  3. Again I kept design of the graph simple. I have a line in the graph to easily show where zero is. the points are large and easy to see. The theme used here is a minimal theme. I used a SET2 palette to make the colors pop against the white background.

Interactive Visualization

Go to Interactive_Viz.R and select run app to load up interactive bar graph. Below is a screenshot of the app for reference purposes.

Shiny App requires loading up

Go to Interactive_Viz.R and select run app to load up Shiny interactive bar graph. Above is a screenshot of the app for reference purposes.

  1. For my final visualization I wanted to create a shiny application. I decided on displaying the running information for each distance segment on a bar graph and I wanted to make it selectable for each runner in the marathon. I later decided to make a second selectable pull down menu so you can compare two runners information to each other. To prepare the data I had to filter out all the missing or bad data. I also had to cut down the size of my data frame to 300 because large sizes were causing errors.

  2. This map allows an interesting story , you can select two different runners. You can compare their different times at each distance. On the left side you get personal information about the runner such as name, sex, country of origin and age. I used up nearly all the variable information in the dataframe and feel I represented it well in the graph. I had difficulty with the dataframe at full size and had to limit the graph to the top 300 participants. I think I was running out of memory on my computer with a larger dataset, but I am not sure.

  3. The interactive visualization is fairly self explanatory On the left in a clearly marked box you can select between two drop menus. The names for the top 300 runners are in each menu. When you select participant their information is listed below and the graph to right is updated to display each runners times per distance run along with their pace. You can then directly compare two runners. I chose bar graphs because they easily display the information and fill up the available space to make it easy to see. I kept the rest of the graph simple with easy to understand legend and labels and used a minimal theme. I chose the colors yellow and blue because they are the colors of the Boston Marathon and very close to being complimentary colors. I decided on changing from seconds to minutes because people understand minutes in large numbers more than seconds.

LS0tDQp0aXRsZTogIkRhdGEgVmlzdWFsaXphdGlvbiAtIE1pbmktUHJvamVjdCAyIg0KYXV0aG9yOiAiQWxleGFuZGVyIEh1Z2hlcyBgYWh1Z2hlczMzMDBAZmxvcmlkYXBvbHkuZWR1YCINCm91dHB1dDoNCiAgaHRtbF9kb2N1bWVudDoNCiAgICBkZl9wcmludDogcGFnZWQNCi0tLQ0KDQpgYGB7cn0NCmxpYnJhcnkodGlkeXZlcnNlKQ0KbGlicmFyeSh1c21hcCkNCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkoYnJvb20pDQpsaWJyYXJ5KGx1YnJpZGF0ZSkNCmxpYnJhcnkocGxvdGx5KQ0KYGBgDQoNCmBgYHtyfQ0KIyMjIFJlYWQgaW4gZGF0YQ0KbWFyYXRob25fdXNhX3NleF9wYWNlIDwtIHJlYWRfY3N2KCJkYXRhL21hcmF0aG9uX3VzYV9zZXhfcGFjZS5jc3YiKQ0KDQojIyMgY3JlYXRlIGEgY2hvcm9wbGV0aA0KcCA8LSBwbG90X3VzbWFwKGRhdGEgPSBtYXJhdGhvbl91c2Ffc2V4X3BhY2UsIHZhbHVlcyA9ICJudW1iZXIiLCBjb2xvciA9ICJibGFjayIsKStzY2FsZV9zaXplX2NvbnRpbnVvdXMocmFuZ2UgPSBjKG1pbihtYXJhdGhvbl91c2Ffc2V4X3BhY2UkbiksIG1heChtYXJhdGhvbl91c2Ffc2V4X3BhY2UkbikpKSsgIHNjYWxlX2ZpbGxfY29udGludW91cygNCiAgICBsb3cgPSAiI0ZFRUJFNyIsIGhpZ2ggPSAicmVkIiwgbmFtZSA9ICJUb3RhbCIsIGxhYmVsID0gc2NhbGVzOjpjb21tYQ0KICApICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInJpZ2h0IikrDQogIGZhY2V0X3dyYXAofiBTZXgsbmNvbCA9IDEsbGFiZWxsZXIgPSBhc19sYWJlbGxlcihjKCdGJyA9ICJOdW1iZXIgb2YgRmVtYWxlIFBhcml0aWNwYW50cyIsICdNJyA9ICJOdW1iZXIgb2YgTWFsZSBQYXJ0aWNpcGFudHMiKSkpICtnZ3RpdGxlKGxhYmVsID0gIkJvc3RvbiBNYXJhdGhvbiAyMDE3IikNCg0KcDI8LXAgKyB0aGVtZSgNCiAgbGVnZW5kLnBvc2l0aW9uID0gYygxLCAuMyksIA0KICBsZWdlbmQuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gIndoaXRlIiwgY29sb3VyID0gTkEpLA0KICBzdHJpcC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLA0KIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT0yMCksDQogc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTE1KSwNCiBwYW5lbC5zcGFjaW5nID0gdW5pdCgyLCAibGluZXMiKSwNCiAgcGxvdC5jYXB0aW9uID0gZWxlbWVudF90ZXh0KCJTdGF0ZSBvZiBQYXJ0aWNpcGFudHMgT3JpZ2luIikNCiANCikNCiNnZ3Bsb3RseShwMikgDQpgYGANCg0KDQojIyMjbW9kZWwNCg0KYGBge3J9DQoNCiMjIyByZWFkIGluIGFuZCBwcm9jZXNzIGRhdGENCm1hcmF0aG9uIDwtIHJlYWRfY3N2KCJkYXRhL21hcmF0aG9uLmNzdiIpDQptYXJhdGhvbiA8LSBuYS5vbWl0KG1hcmF0aG9uKQ0KbWFyYXRob24kSGFsZjwtIGhtcyhtYXJhdGhvbiRIYWxmKQ0KbWFyYXRob24kT2ZmaWNpYWxUaW1lPC0gaG1zKG1hcmF0aG9uJE9mZmljaWFsVGltZSkNCm1hcmF0aG9uJHRlbks8LSBobXMobWFyYXRob24kdGVuSykNCm1hcmF0aG9uJHRoaXJ0eUs8LSBobXMobWFyYXRob24kdGhpcnR5SykNCm1hcmF0aG9uJFBhY2U8LSBobXMobWFyYXRob24kUGFjZSkNCg0KbWFyYXRob24kSGFsZjwtIGFzLm51bWVyaWMobWFyYXRob24kSGFsZikNCm1hcmF0aG9uJE9mZmljaWFsVGltZTwtIGFzLm51bWVyaWMobWFyYXRob24kT2ZmaWNpYWxUaW1lKQ0KbWFyYXRob24kdGVuSzwtIGFzLm51bWVyaWMobWFyYXRob24kdGVuSykNCm1hcmF0aG9uJHRoaXJ0eUs8LSBhcy5udW1lcmljKG1hcmF0aG9uJHRoaXJ0eUspDQptYXJhdGhvbiRQYWNlPC0gYXMubnVtZXJpYyhtYXJhdGhvbiRQYWNlKQ0KDQpgYGANCg0KYGBge3J9DQojIyMgY3JlYXRlIG1vZGVscw0KbTJfbW9kZWwgPC0gbG0oT2ZmaWNpYWxUaW1lIH4gdGVuSyArIEhhbGYgKyB0aGlydHlLLA0KICAgICAgICAgICAgICAgICAgICBkYXRhID0gbWFyYXRob24pDQp0aWR5KG0yX21vZGVsKQ0KbTJfY29lZnMgPC0gdGlkeShtMl9tb2RlbCwgY29uZi5pbnQgPSBUUlVFKSAlPiUgDQogIGZpbHRlcih0ZXJtICE9ICIoSW50ZXJjZXB0KSIpICANCiNtMl9jb2Vmcw0KbTNfbW9kZWwgPC0gbG0oT2ZmaWNpYWxUaW1lIH4gdGVuSyArIEhhbGYgKyB0aGlydHlLK0FnZSwNCiAgICAgICAgICAgICAgICAgICAgZGF0YSA9IG1hcmF0aG9uKQ0KdGlkeShtM19tb2RlbCkNCm0zX2NvZWZzIDwtIHRpZHkobTNfbW9kZWwsIGNvbmYuaW50ID0gVFJVRSkgJT4lIA0KICBmaWx0ZXIodGVybSAhPSAiKEludGVyY2VwdCkiKSAgDQojbTNfY29lZnMNCmBgYA0KDQpgYGB7cn0NCiMjI2NyZWF0ZSBjb2VmZmljZW50IHBsb3QNCmxhYmxlczI8LWMoIjMwSyIsIjEwSyIsICJIYWxmIFJhY2UiLCJBZ2UiKQ0KDQpwY288LWdncGxvdChtM19jb2VmcywNCiAgICAgICBhZXMoeCA9IGVzdGltYXRlLCANCiAgICAgICAgICAgeSA9IGZjdF9yZXYodGVybSkpKSArDQogIGdlb21fcG9pbnRyYW5nZShhZXMoeG1pbiA9IGNvbmYubG93LCANCiAgICAgICAgICAgICAgICAgICAgICB4bWF4ID0gY29uZi5oaWdoLCBjb2xvcj1mY3RfcmV2KHRlcm0pKSxzaXplPS43NSkgKw0KICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwLCANCiAgICAgICAgICAgICBjb2xvciA9ICJwdXJwbGUiKSArIA0KICBzY2FsZV9jb2xvcl9icmV3ZXIocGFsZXR0ZT0iU2V0MSIpKw0KICB0aGVtZV9taW5pbWFsKCkrbGFicyh0aXRsZSA9ICJMaW5lYXIgTW9kZWwgQ29lZmZpY2VudHMgZm9yIEZpbmlzaCBUaW1lIiwgeD0gIkVzdGltYXRlIENvZWZmaWNlbnQiLCB5PSJEaXN0YW5jZSBSdW4iKStzY2FsZV9jb2xvcl9kaXNjcmV0ZShuYW1lPSJEaXN0YW5jZSBSdW4iLCBsYWJlbHM9bGFibGVzMikrc2NhbGVfeV9kaXNjcmV0ZShsYWJlbHM9bGFibGVzMikNCiNwY28NCmBgYA0KDQoNCg0KYGBge3J9DQpnZ3Bsb3RseShwMikgDQpgYGANCiMjIFNwYXRpYWwgVmlzdWFsaXphdGlvbg0KDQoxLiAgV2hhdCBJIG9yaWdpbmFsbHkgd2FudGVkIHRvIG1ha2Ugd2FzIGEgd29ybGQgbWFwIHNob3dpbmcgdGhlIHBhcnRpY2lwYW50cyBvcmlnaW5zLiBIb3dldmVyIHdoZW4gZ29pbmcgdGhyb3VnaCB0aGUgZGF0YSBpdCBiZWNvbWUgYXBwYXJlbnQgdGhhdCB0aGVyZSB3YXNuJ3QgaGlnaCBudW1iZXIgcGFydGljaXBhbnRzIHJlcHJlc2VudGVkIG91dHNpZGUgdGhlIFVTQSBpbiBjb21wYXJpc29uIHRvIGluc2lkZSB0aGUgVVNBLiBTbyBJIHN3aXRjaGVkIHRvIGEgVVNBIG1hcCBhbmQgZGVjaWRlZCB0byBzaG93IHRoZSBwYXJ0aWNpcGFudHMgYnkgc3RhdGUuIEkgZnVydGhlciBkaXZpZGVkIHRoZSBkYXRhIGJ5IFNleCB0byBzZWUgaWYgdGhlcmUgd2VyZSBhbnkgdmlzdWFsIGRpZmZlcmVuY2VzLiBUaGUgc3RlcHMgSSB0b29rIHdlcmUgZmlsdGVyaW5nIG91dCB0aGUgbm9uIFVTQSBwYXJ0aWNpcGFudHMgYW5kIHRoZW4gZnVydGhlciBkaXZpZGluZyB0aGVtIHVwIGJ5IHNleC4gSSB0aGVuIHN1bW1lZCB0aGUgYW1vdW50IG9mIGVhY2ggcGVyIHN0YXRlIGFuZCBjcmVhdGVkIGEgbmV3IGRhdGEgZnJhbWUgdG8gZ3JhcGggdGhlIGRhdGEuIEZpbmFsbHkgSSB3YW50ZWQgdG8gaGF2ZSBzb21ldGhpbmcgaW50ZXJhY3RpdmUgc28gSSBkZWNpZGVkIHRvIHVzZSBnZ3Bsb3RseSBzbyB5b3UgY2FuIHNlZSB0aGUgaW5kaXZpZHVhbCBudW1iZXJzIHBlciBzdGF0ZS4NCg0KMi4gIExvb2tpbmcgYXQgdGhpcyBtYXAgeW91IGNhbiBzZWUgdHdvIHRoaW5ncy4gVGhhdCB0aGUgZ2VuZXJhbCBkaXN0cmlidXRpb24gb2YgbWFsZSBhbmQgZmVtYWxlIHBhcnRpY2lwYW50cyBpcyB2ZXJ5IHNpbWlsYXIgYXMgdGhlIGNvbG9ycyBmb3IgZWFjaCBzdGF0ZSBsb29rIHNpbWlsYXIuIEFsc28geW91IGNhbiBzZWUgd2hpY2ggc3RhdGVzIGhhdmUgdGhlIG1vc3QgcGFydGljaXBhbnRzIHdpdGggTWFzc2FjaHVzZXR0cyBoYXZpbmcgdGhlIG1vc3QuIFRoaXMgbWFrZXMgc2Vuc2UgYmVjYXVzZSB0aGUgbWFyYXRob24gaXMgaG9zdGVkIGluIEJvc3Rvbi4gSG93ZXZlciB3aGF0cyBpbnRlcmVzdGluZyB0aGUgc2Vjb25kIHN0YXRlIGlzIENhbGlmb3JuaWEuIEkgdGhpbmsgdGhpcyBpcyBpbnRlcmVzdGluZyBiZWNhdXNlIENhbGlmb3JuaWEgaXMgc28gZmFyIGF3YXkgZnJvbSBNYXNzYWNodXNldHRzLiBJdCdzIGFsc28gZnVuIHRvIHNlZSB0aGF0IHRoZXkgYWxzbyBoYWQgcGFydGljaXBhbnRzIGZyb20gQWxhc2thIGFuZCBIYXdhaWkuDQoNCjMuICBJIGtlcHQgdGhlIGRlc2lnbiBzaW1wbGUgYW5kIHVzZWQgYSBiYXNlIHJlZCBjb2xvciB0byBtYWtlIHRoZSBwb3B1bGF0aW9ucyBzdGFuZCBvdXQgbW9yZSwgYW5kIGtlcHQgaXQgdG8gb25lIGNvbG9yLiBJIG1hZGUgdGhlIHRpdGxlIGxlZnQgYWxpZ25lZCBiZWNhdXNlIHRoZSB2aWV3ZXJzIGV5ZXMgdGVuZCB0byB2aWV3IHRoZSBsZWZ0LiBJIHVzZWQgYSBmYWNldCBzdHlsZSBncmFwaCB0byBzaG93IHNpZGUgYnkgc2lkZSB0aGUgbWFsZSBhbmQgZmVtYWxlIHBhcnRpY2lwYW50cyBpbiBhIHdheSB0aGF0IHdhcyBlYXN5IHRvIHNlZS4gSSB1c2VkIGdncGxvdHkgdG8gbWFrZSB0aGUgbWFwIGludGVyYWN0aXZlIHNvIHlvdSBjYW4gaG92ZXIgb3ZlciBldmVyeSBwbG90IGFuZCBzZWUgdGhlIG51bWJlcnMuIFRoaXMgZHJhd3MgaW4gdGhlIHVzZXIgdG8gdXNlIHRoZSBtYXAuDQoNCmBgYHtyfQ0KZ2dwbG90KCkgKw0KICBnZW9tX3Ntb290aChhZXMoeCA9IHRlbkssIHkgPSBPZmZpY2lhbFRpbWUpLCBkYXRhID0gbTJfbW9kZWwsIA0KICAgICAgICAgICAgICBtZXRob2QgPSAibG0iLCBzZSA9IEZBTFNFLCBjb2xvciA9ICJyZWQ0IikgKyANCiAgZ2VvbV9zbW9vdGgoYWVzKHggPSBIYWxmLCB5ID0gT2ZmaWNpYWxUaW1lKSwgZGF0YSA9IG0yX21vZGVsLCANCiAgICAgICAgICAgICAgbWV0aG9kID0gImxtIiwgc2UgPSBGQUxTRSwgY29sb3IgPSAiYmx1ZTQiKSArIA0KICBnZW9tX3Ntb290aChhZXMoeCA9IHRoaXJ0eUssIHkgPSBPZmZpY2lhbFRpbWUpLCBkYXRhID0gbTJfbW9kZWwsIA0KICAgICAgICAgICAgICBtZXRob2QgPSAibG0iLCBzZSA9IEZBTFNFLCBjb2xvciA9ICJncmVlbjQiKSArIA0KICBnZW9tX3BvaW50KGFlcyh4ID0gdGVuSywgeSA9IE9mZmljaWFsVGltZSksIGRhdGEgPSBtMl9tb2RlbCwgY29sb3IgPSAicmVkIixhbHBoYSA9IDAuMDIpKw0KICBnZW9tX3BvaW50KGFlcyh4ID0gSGFsZiwgeSA9IE9mZmljaWFsVGltZSksIGRhdGEgPSBtMl9tb2RlbCwgY29sb3IgPSAiYmx1ZSIsYWxwaGEgPSAwLjAyKSArDQogIGdlb21fcG9pbnQoYWVzKHggPSB0aGlydHlLLCB5ID0gT2ZmaWNpYWxUaW1lKSwgZGF0YSA9IG0yX21vZGVsLCBjb2xvciA9ICJncmVlbiIsYWxwaGEgPSAwLjAyKSsgDQphbm5vdGF0ZSgndGV4dCcsIHggPSA1MTAwLCB5ID0gMjcwMDAsIGxhYmVsID0gJ1RlbiBLJyxzaXplID0gNSxhbmdsZT0nNjgnLCBjb2xvcj0gJ3JlZDQnKSsgDQphbm5vdGF0ZSgndGV4dCcsIHggPSAxMTAwMCwgeSA9IDI1NTAwLCBsYWJlbCA9ICdIYWxmIFJhY2UnLHNpemUgPSA1LGFuZ2xlPSc1MScsIGNvbG9yPSAnYmx1ZTQnKSsgDQphbm5vdGF0ZSgndGV4dCcsIHggPSAxODAwMCwgeSA9IDI3NTAwLCBsYWJlbCA9ICdUaHJpdHkgSycsc2l6ZSA9IDUsYW5nbGU9JzQxJywgY29sb3I9ICdncmVlbjQnKStsYWJzKA0KICB0aXRsZSA9ICJMaW5lYXIgTW9kZWwgTGluZSBmb3IgT2ZmaWNhbCBUaW1lIGJ5IERpc3RhbmNlIFRpbWUiLCB4PSAiRGlzdGFuY2UgVGltZSBpbiBTZWNvbmRzIiwgeT0iRmluaXNoIFRpbWUgaW4gU2Vjb25kcyIpK3RoZW1lX21pbmltYWwoKQ0KDQoNCmBgYA0KDQojIyBMaW5lYXIgTW9kZWwgTGluZSBQbG90DQoNCjEuICBGb3IgdGhlIG1vZGVsIEkgb3JpZ2luYWxseSBwbGFuZWQgdG8gY3JlYXRlIGEgbGluZSB3aXRoIGdlb21fc21vb3RoIGFuZCBhIGxpbmVhciBtb2RlbC4gSSBjcmVhdGVkIGEgIGxpbmVhciBtb2RlbCB0aGVuIHVzZWQgdGhlIGxpbmVhciBtb2RlbCBkYXRhIHRvIGRyYXcgdGhyZWUgbGluZXMgd2l0aCBpdHMgYXNzb2NpYXRlZCBwbG90IGNsb3VkLiBJIGFsc28gaGFkIHRvIGNvbnZlcnQgdGhlIHRpbWUgdG8gc2Vjb25kcy4gSSBhbHNvIG9yaWdpbmFsbHkgd2FudGVkIHRvIHBsb3QgYWdlIGJ1dCBpdCBkaWRuJ3QgdHVybiBvdXQgZ29vZC4NCg0KMi4gIExvb2tpbmcgYXQgdGhlIGRhdGEgeW91IGNhbiBzZWUgdGhlIHBsb3QgY2xvdWQgZm9yIHRoZSB0aHJlZSBkaWZmZXJlbnQgZGlzdGFuY2VzIG92ZXIgRmluaXNoIHRpbWUuIFlvdSBjYW4gc2VlIHdoZXJlIGVhY2ggZGlzdGFuY2UgYXMgYSBsaW5lYXIgbW9kZWwgYW5kIGhvdyBpdCBhc3NvY2lhdGVzIHdpdGggd2hhdCBpdCBwcmVkaWN0cyB3aGVyZSB0aGUgZmluaXNoIHRpbWUgc2hvdWxkIGJlIGNvbXBhcmVkIHRvIHRoZSB0aW1lIGF0IHRoZSBhc3NvY2lhdGVkIGRpc3RhbmNlLiBZb3UgY2FuIHNlZSB0aGUgc2xvcGVzIG9mIHRoZSBwcmVkaWN0ZWQgbGluZXMuIFRoZSBzdG9yeSB5b3UgY2FuIHRlbGwgaGVyZSBpcyB5b3UgY2FuIGZvbGxvdyB0aGUgbGluZSBhbmQgc2VlIGlmIHlvdSBwYXNzZWQgYSBkaXN0YW5jZSBhdCB4IHRpbWUgeW91ciBmaW5pc2ggdGhlbSB3aWxsIGxpa2VseSBiZSB5IHRpbWUuIEEgcnVubmVyIGNhbiB1c2UgdGhpcyB0byB0YXJnZXQgdGltZXMgdGhleSBuZWVkIHRvIG1lZXQuIFRoaXMgaXMgZm9sbG93ZWQgZm9yIGVhY2ggb2YgdGhlIHRocmVlIGRpc3RhbmNlcy4gSSBoYWQgZGlmZmljdWx0eSBoZXJlIGFkZGluZyBBZ2UgYXMgYSBjb21wb25lbnQgaXQgZG9lc24ndCBzZWVtIHRvIGNyZWF0ZSBhIHVzYWJsZSBsaW5lLg0KDQozLiAgSSBjb250aW51ZWQgdG8ga2VlcCB0aGUgZGVzaWduIHNpbXBsZSB3aXRoIGJyaWdodCBjb2xvcnMgdG8gY2xhc2ggYWdhaW5zdCB0aGUgd2hpdGUgYmFja2dyb3VuZC4gSSdtIGEgZmFuIG9mIHRoZW1lX21pbmltYWwgYW5kIHRoaW5rIGl0IGRvZXMgYSBnb29kIGpvYiBvZiBkZWNsdXR0ZXJpbmcgdGhlIGdyYXBoLiBJIGFkZGVkIGEgb3BhY2l0eSB0byB0aGUgcGxvdCBwb2ludHMgYmVjYXVzZSB0aGV5IHdlcmUgc28gdGhpY2sgeW91IGNvdWxkbid0IHNlZSB0aGUgbGluZXMuIEZvciBlYWNoIGxpbmUgSSBhZGRlZCBhbiBhbm5vdGF0aW9uIHRvIGlkZW50aWZ5IHdoaWNoIGxpbmUgZ29lcyB0byB3aXRoIHZhcmlhYmxlIGRpc3RhbmNlLg0KDQpgYGB7cn0NCnBjbw0KYGBgDQoNCiMjIE1vZGVsIFZpc3VhbGl6YXRpb24gQ29lZmZpY2llbnQgUGxvdA0KDQoxLiAgRm9yIHRoZSBtb2RlbCBJIG9yaWdpbmFsbHkgcGxhbmVkIHRvIGNyZWF0ZSBhIGNvZWZmaWNpZW50IHBsb3QuIEkgd2FudGVkIHRvIGhhdmUgbW9yZSBlbGVtZW50cyBvcmlnaW5hbGx5IGJ1dCBJIGRlY2lkZWQgdG8ga2VlcCBpdCBzaW1wbGUgYW5kIGxpbWl0IGl0IHRvIGZvdXIgcGxvdCBlbGVtZW50cywgZWFybHkgaW4gdGhlIHJhY2UsIG1pZGRsZSBvZiB0aGUgcmFjZSBhbmQgbGF0ZSBpbiB0aGUgcmFjZSBhbmQgZmluYWxseSBhZ2UuIEkgZm91bmQgdGhhdCBhZGRpbmcgbW9yZSBkaXN0YW5jZXMgd2FzIHNvbWV3aGF0IHJlZHVuZGFudCBhbmQgY29tcGxpY2F0ZWQgdGhlIG1vZGVsLiBUaGUgc3RlcHMgSSB0b29rIHdlcmUgcnVubmluZyB0aGUgdmFyaWFibGVzIHRocm91Z2ggYSBsaW5lYXIgbW9kZWwsIHRoZW4gZ2V0dGluZyB0aGUgY29lZmZpY2llbnRzIGFuZCBjb252ZXJ0aW5nIHRoZSBpbmZvcm1hdGlvbiBpbnRvIHRvIHRpZHkgZGF0YS4NCg0KMi4gIExvb2tpbmcgYXQgdGhpcyBtYXAgeW91IGNhbiBzZWUgdGhlIGNvZWZmaWNpZW50cyBhbmQgaXQgaGFzIGEgdmVydGljYWwgbGluZSBhdCB6ZXJvLiBQb2ludHMgdGhhdCBhcmUgY2xvc2UgdG8gdGhlIHplcm8gZG9uJ3QgaGF2ZSBtdWNoIGJlYXJpbmcgb24gdGhlIG91dGNvbWUuIExvb2tpbmcgYXQgdGhlIHBsb3RzIHlvdSBjYW4gc2VlIHRoYXQgMTBLIGlzIGNsb3NlIHRvIHRoZSB6ZXJvIGxpbmUuIFlvdSBjYW4gYWxzbyBzZWUgdGhhdCBIYWxmIHJhY2UgaGFzIGEgdmFsdWUgb2YgLTEuMyB3aGljaCBoYXMgYSBuZWdhdGl2ZSBpbmZsdWVuY2Ugb24gdGhlIG91dGNvbWUgYW5kIHRoYXQgMzBLIGlzIDIuMyBwb3NpdGl2ZSBhbmQgaGFzIHZlcnkgc3Ryb25nIGJlYXJpbmcgb24gdGhlIG92ZXJjb21lIG9mIHRoZSBGaW5pc2ggVGltZS4gVGhlIFN0b3J5IGhlcmUgaXMgdGhhdCBob3cgeW91IGRvIGVhcmx5IGluIHRoZSByYWNlIGhhcyBtdWNoIGxlc3MgZWZmZWN0IG9uIHlvdXIgZmluaXNoaW5nIHRpbWUgdGhhbiBob3cgeW91IGRvIGxhdGVyIGluIHRoZSByYWNlLiBPbmUgbGFzdCBjb2VmZmljaWVudCBJIHRocmV3IGluIGhlcmUgZm9yIHRoZSBncmFwaCBpcyBBZ2UsIHlvdSBzZWUgdGhhdCBBZ2UgYWdlIGhhcyBsYXJnZSBiZWFyaW5nIG9uIHlvdXIgRmluaXNoIFRpbWUuIERpZmZpY3VsdGllcyBJIGhhZCB3ZXJlIHRoZSBsaW5lYXIgbW9kZWwgZnVuY3Rpb24gaW4gUiB3b3VsZCBub3QgdGFrZSBpdCBpbiB0aW1lIHByb3Blcmx5IEkgaGFkIHRvIGNoYW5nZSBhbGwgdGhlIHRpbWVzIHRvIHNlY29uZHMuDQoNCjMuICBBZ2FpbiBJIGtlcHQgZGVzaWduIG9mIHRoZSBncmFwaCBzaW1wbGUuIEkgaGF2ZSBhIGxpbmUgaW4gdGhlIGdyYXBoIHRvIGVhc2lseSBzaG93IHdoZXJlIHplcm8gaXMuIHRoZSBwb2ludHMgYXJlIGxhcmdlIGFuZCBlYXN5IHRvIHNlZS4gVGhlIHRoZW1lIHVzZWQgaGVyZSBpcyBhIG1pbmltYWwgdGhlbWUuIEkgdXNlZCBhIFNFVDIgcGFsZXR0ZSB0byBtYWtlIHRoZSBjb2xvcnMgcG9wIGFnYWluc3QgdGhlIHdoaXRlIGJhY2tncm91bmQuDQoNCiMjIEludGVyYWN0aXZlIFZpc3VhbGl6YXRpb24NCg0KIyMjIyBHbyB0byBJbnRlcmFjdGl2ZV9WaXouUiBhbmQgc2VsZWN0IHJ1biBhcHAgdG8gbG9hZCB1cCBpbnRlcmFjdGl2ZSBiYXIgZ3JhcGguIEJlbG93IGlzIGEgc2NyZWVuc2hvdCBvZiB0aGUgYXBwIGZvciByZWZlcmVuY2UgcHVycG9zZXMuDQoNCiFbXShpbnRlcmFjdGl2ZV9zY3JlZW5zaG90LnBuZykNCg0KKioqU2hpbnkgQXBwIHJlcXVpcmVzIGxvYWRpbmcgdXAqKioNCg0KKipHbyB0byBJbnRlcmFjdGl2ZV9WaXouUiBhbmQgc2VsZWN0IHJ1biBhcHAgdG8gbG9hZCB1cCBTaGlueSBpbnRlcmFjdGl2ZSBiYXIgZ3JhcGguIEFib3ZlIGlzIGEgc2NyZWVuc2hvdCBvZiB0aGUgYXBwIGZvciByZWZlcmVuY2UgcHVycG9zZXMuKioNCg0KMS4gIEZvciBteSBmaW5hbCB2aXN1YWxpemF0aW9uIEkgd2FudGVkIHRvIGNyZWF0ZSBhIHNoaW55IGFwcGxpY2F0aW9uLiBJIGRlY2lkZWQgb24gZGlzcGxheWluZyB0aGUgcnVubmluZyBpbmZvcm1hdGlvbiBmb3IgZWFjaCBkaXN0YW5jZSBzZWdtZW50IG9uIGEgYmFyIGdyYXBoIGFuZCBJIHdhbnRlZCB0byBtYWtlIGl0IHNlbGVjdGFibGUgZm9yIGVhY2ggcnVubmVyIGluIHRoZSBtYXJhdGhvbi4gSSBsYXRlciBkZWNpZGVkIHRvIG1ha2UgYSBzZWNvbmQgc2VsZWN0YWJsZSBwdWxsIGRvd24gbWVudSBzbyB5b3UgY2FuIGNvbXBhcmUgdHdvIHJ1bm5lcnMgaW5mb3JtYXRpb24gdG8gZWFjaCBvdGhlci4gVG8gcHJlcGFyZSB0aGUgZGF0YSBJIGhhZCB0byBmaWx0ZXIgb3V0IGFsbCB0aGUgbWlzc2luZyBvciBiYWQgZGF0YS4gSSBhbHNvIGhhZCB0byBjdXQgZG93biB0aGUgc2l6ZSBvZiBteSBkYXRhIGZyYW1lIHRvIDMwMCBiZWNhdXNlIGxhcmdlIHNpemVzIHdlcmUgY2F1c2luZyBlcnJvcnMuDQoNCjIuICBUaGlzIG1hcCBhbGxvd3MgYW4gaW50ZXJlc3Rpbmcgc3RvcnkgLCB5b3UgY2FuIHNlbGVjdCB0d28gZGlmZmVyZW50IHJ1bm5lcnMuIFlvdSBjYW4gY29tcGFyZSB0aGVpciBkaWZmZXJlbnQgdGltZXMgYXQgZWFjaCBkaXN0YW5jZS4gT24gdGhlIGxlZnQgc2lkZSB5b3UgZ2V0IHBlcnNvbmFsIGluZm9ybWF0aW9uIGFib3V0IHRoZSBydW5uZXIgc3VjaCBhcyBuYW1lLCBzZXgsIGNvdW50cnkgb2Ygb3JpZ2luIGFuZCBhZ2UuIEkgdXNlZCB1cCBuZWFybHkgYWxsIHRoZSB2YXJpYWJsZSBpbmZvcm1hdGlvbiBpbiB0aGUgZGF0YWZyYW1lIGFuZCBmZWVsIEkgcmVwcmVzZW50ZWQgaXQgd2VsbCBpbiB0aGUgZ3JhcGguIEkgaGFkIGRpZmZpY3VsdHkgd2l0aCB0aGUgZGF0YWZyYW1lIGF0IGZ1bGwgc2l6ZSBhbmQgaGFkIHRvIGxpbWl0IHRoZSBncmFwaCB0byB0aGUgdG9wIDMwMCBwYXJ0aWNpcGFudHMuIEkgdGhpbmsgSSB3YXMgcnVubmluZyBvdXQgb2YgbWVtb3J5IG9uIG15IGNvbXB1dGVyIHdpdGggYSBsYXJnZXIgZGF0YXNldCwgYnV0IEkgYW0gbm90IHN1cmUuDQoNCjMuICBUaGUgaW50ZXJhY3RpdmUgdmlzdWFsaXphdGlvbiBpcyBmYWlybHkgc2VsZiBleHBsYW5hdG9yeSBPbiB0aGUgbGVmdCBpbiBhIGNsZWFybHkgbWFya2VkIGJveCB5b3UgY2FuIHNlbGVjdCBiZXR3ZWVuIHR3byBkcm9wIG1lbnVzLiBUaGUgbmFtZXMgZm9yIHRoZSB0b3AgMzAwIHJ1bm5lcnMgYXJlIGluIGVhY2ggbWVudS4gV2hlbiB5b3Ugc2VsZWN0IHBhcnRpY2lwYW50IHRoZWlyIGluZm9ybWF0aW9uIGlzIGxpc3RlZCBiZWxvdyBhbmQgdGhlIGdyYXBoIHRvIHJpZ2h0IGlzIHVwZGF0ZWQgdG8gZGlzcGxheSBlYWNoIHJ1bm5lcnMgdGltZXMgcGVyIGRpc3RhbmNlIHJ1biBhbG9uZyB3aXRoIHRoZWlyIHBhY2UuIFlvdSBjYW4gdGhlbiBkaXJlY3RseSBjb21wYXJlIHR3byBydW5uZXJzLiBJIGNob3NlIGJhciBncmFwaHMgYmVjYXVzZSB0aGV5IGVhc2lseSBkaXNwbGF5IHRoZSBpbmZvcm1hdGlvbiBhbmQgZmlsbCB1cCB0aGUgYXZhaWxhYmxlIHNwYWNlIHRvIG1ha2UgaXQgZWFzeSB0byBzZWUuIEkga2VwdCB0aGUgcmVzdCBvZiB0aGUgZ3JhcGggc2ltcGxlIHdpdGggZWFzeSB0byB1bmRlcnN0YW5kIGxlZ2VuZCBhbmQgbGFiZWxzIGFuZCB1c2VkIGEgbWluaW1hbCB0aGVtZS4gSSBjaG9zZSB0aGUgY29sb3JzIHllbGxvdyBhbmQgYmx1ZSBiZWNhdXNlIHRoZXkgYXJlIHRoZSBjb2xvcnMgb2YgdGhlIEJvc3RvbiBNYXJhdGhvbiBhbmQgdmVyeSBjbG9zZSB0byBiZWluZyBjb21wbGltZW50YXJ5IGNvbG9ycy4gSSBkZWNpZGVkIG9uIGNoYW5naW5nIGZyb20gc2Vjb25kcyB0byBtaW51dGVzIGJlY2F1c2UgcGVvcGxlIHVuZGVyc3RhbmQgbWludXRlcyBpbiBsYXJnZSBudW1iZXJzIG1vcmUgdGhhbiBzZWNvbmRzLg0K